package com.minibobbo.utilities.particles;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;

public class ParticleSystem {
	Particle[] basic;

	// A single white pixel for drawing.
	Texture pixel;

	Vector2 gravity;

	Color expPri = Color.YELLOW;
	Color expSec = Color.RED;

	Array<emitter> emit;

	public ParticleSystem() {
		Pixmap p = new Pixmap(1, 1, Format.RGBA8888);
		p.drawPixel(0, 0, 0xffffffff);
		pixel = new Texture(p);
		basic = new Particle[500];
		for (int i = 0; i < 500; i++) {
			basic[i] = new Particle();
			basic[i].setTextureRegion(pixel);
		}
		gravity = new Vector2();
		emit = new Array<emitter>();
	}

	public void CreateEmitter(String label, Vector2 loc, Vector2 direction,
			float spread, Vector2 gravity, Color primary, Color secondary,
			int particleCount, float particleDuration, float emitterDuration) {
		emitter e = new emitter(label, loc, direction, spread, gravity,
				primary, secondary, particleCount, particleDuration,
				emitterDuration);
		e.setDuration(emitterDuration);

		Gdx.app.log("Trying to create emitter", e.emitterDuration + "");

		emit.add(e);
	}

	/**
	 * Updates all the particles that are controlled by this system and not the
	 * Box2D world.
	 * 
	 * @param delta
	 *            Elapsed time
	 */
	public void update(float delta) {
		// Updates all the basic particles
		int count = 0;
		for (Particle p : basic) {
			p.update(delta);
			if (p.active)
				count++;
		}
		// Gdx.app.log("Particle count", count + "");

		for (emitter e : emit) {
			if (e.dispose)
				emit.removeValue(e, false);
			else
				e.update(delta);
		}
	}

	public void draw(SpriteBatch sb) {
		for (Particle p : basic)
			p.draw(sb);

	}

	/**
	 * Simulate an explosion with particles
	 * @param x X loc
	 * @param y Y loc
	 * @param size
	 *            Size of each particle
	 * @param strength
	 *            Strength of the explosion. Higher is bigger.
	 */
	public void Explosion(float x, float y, float size, float strength) {
		for (int i = 0; i < strength * 5; i++) {
			spawnParticle(size, expSec, x, y,
					MathUtils.random(-strength / 2, strength / 2),
					MathUtils.random(-strength / 2, strength / 2),
					MathUtils.random(.5f, strength / 3));
			spawnParticle(size, expPri, x, y,
					MathUtils.random(-strength / 3, strength / 3),
					MathUtils.random(-strength / 3, strength / 3),
					MathUtils.random(.5f, strength / 5));
			gravity = gravity;
		}
	}

	/**
	 * Gravity that effect's the particles.
	 * 
	 * @param x
	 * @param y
	 */
	public void setGravity(float x, float y) {
		gravity.x = x;
		gravity.y = y;
	}

	/**
	 * Spawns a particle
	 * 
	 * @param size
	 *            Size to spawn
	 * @param c
	 *            Color
	 * @param xLoc
	 *            X loc
	 * @param yLoc
	 *            Y loc
	 * @param xSpd
	 *            Speed of X
	 * @param ySpd
	 *            Speed of Y
	 * @param duration
	 *            How long should the particle last?
	 * @return
	 */
	public Particle spawnParticle(float size, Color c, float xLoc, float yLoc,
			float xSpd, float ySpd, float duration) {
		Particle tempP = getNextAvailableParticle();
		if (tempP != null) {
			tempP.spawnParticle(size, c, xLoc, yLoc, xSpd, ySpd, duration);
			return tempP;
		}
		return null;
	}

	/**
	 * Spawns a particle
	 * 
	 * @param size
	 *            Size to spawn
	 * @param c
	 *            Color
	 * @param loc
	 *            Location of particle
	 * @param xSpd
	 *            Speed of X
	 * @param ySpd
	 *            Speed of Y
	 * @param duration
	 *            How long should the particle last?
	 */
	public void spawnParticle(float size, Color c, Vector2 loc, float xSpd,
			float ySpd, float duration) {
		Particle tempP = getNextAvailableParticle();
		if (tempP != null)
			tempP.spawnParticle(size, c, loc.x, loc.y, xSpd, ySpd, duration);
	}

	/**
	 * Gets the next available particle
	 * 
	 * @return The particle we found
	 */
	public Particle getNextAvailableParticle() {
		for (Particle p : basic) {
			if (!p.active)
				return p;
		}
		return null;

	}

	public void createEmitter(Vector2 loc) {
		// emit.add(new emitter("test", loc, new Vector2(0,5), 1, gravity,
		// Color.RED, Color.YELLOW, 2,4,10,this));
		emit.add(new emitter(loc));
	}

	private class emitter {
		public String label;
		public Vector2 loc;
		public Vector2 direction;
		public float spread;
		public Vector2 emitGravity;
		public Color emitPrimary;
		public Color emitSecondary;
		public int particleCount;
		public float particleDuration;
		public float emitterDuration;
		public boolean dispose = false;

		public emitter(Vector2 loc) {
			Gdx.app.log("The emitter is accessing the Particle System",
					pixel.toString());
			this.loc = loc;
			particleCount = 2;
			direction = new Vector2(0, 5);
			emitterDuration = 5;
			particleCount = 1;
			emitPrimary = Color.YELLOW;
			this.emitGravity = gravity;
			spread = 1;
		}

		public emitter(String label, Vector2 loc, Vector2 direction,
				float spread, Vector2 gravity, Color primary, Color secondary,
				int particleCount, float particleDuration, float emitterDuration) {
			Gdx.app.log("creating emitter", label + emitterDuration);
			this.label = label;
			this.loc = loc;
			this.direction = direction;
			this.spread = spread;
			this.emitGravity = gravity;
			this.emitPrimary = primary;
			this.emitSecondary = secondary;
			this.particleCount = particleCount;
			this.emitterDuration = emitterDuration;
		}

		public void update(float delta) {
			emitterDuration -= delta;
			if (emitterDuration <= 0) {
				dispose = true;
				Gdx.app.log("Disposing emitter", label + emitterDuration);
			}
			for (int i = 0; i < particleCount; i++) {
				// Vector2 temp = direction.cpy();
				// temp.rotate(MathUtils.random(-1 * (90 * spread), 90 *
				// spread));
				Vector2 tempVector = direction.cpy();
				tempVector.rotate(MathUtils.random(90 * spread));
				Gdx.app.log("Spawning particle", "");
				Particle part = spawnParticle(.5f, emitPrimary, loc.x, loc.y,
						tempVector.x, tempVector.y, 3);
				if (part != null) {
					part.gravity.set(this.emitGravity);
					
				}
			}
		}

		public void setDuration(float duration) {
			emitterDuration = duration;
		}

	}
}
